diff --git a/.changeset/silent-needles-attack.md b/.changeset/silent-needles-attack.md
new file mode 100644
index 0000000000..7ead2b674e
--- /dev/null
+++ b/.changeset/silent-needles-attack.md
@@ -0,0 +1,6 @@
+---
+'@backstage/plugin-scaffolder': patch
+'@backstage/plugin-scaffolder-backend': patch
+---
+
+Added deprecation warnings for `v1alpha1` templates
diff --git a/plugins/scaffolder-backend/src/service/router.test.ts b/plugins/scaffolder-backend/src/service/router.test.ts
index e8aa76a63a..9ca2eef9e6 100644
--- a/plugins/scaffolder-backend/src/service/router.test.ts
+++ b/plugins/scaffolder-backend/src/service/router.test.ts
@@ -64,120 +64,6 @@ const mockUrlReader = UrlReaders.default({
config: new ConfigReader({}),
});
-describe('createRouter - working directory', () => {
- const mockPrepare = jest.fn();
- const mockPreparers = new Preparers();
-
- beforeAll(() => {
- const mockPreparer = {
- prepare: mockPrepare,
- };
- mockPreparers.register('dev.azure.com', mockPreparer);
- });
-
- beforeEach(() => {
- jest.resetAllMocks();
- });
-
- const workDirConfig = (path: string) => ({
- backend: {
- workingDirectory: path,
- },
- });
-
- const template = {
- apiVersion: 'backstage.io/v1alpha1',
- kind: 'Template',
- metadata: {
- annotations: {
- 'backstage.io/managed-by-location': 'url:https://dev.azure.com',
- },
- },
- spec: {
- owner: 'template@backstage.io',
- path: '.',
- schema: {},
- },
- };
-
- it('should throw an error when working directory does not exist or is not writable', async () => {
- mockAccess.mockImplementation(() => {
- throw new Error('access error');
- });
-
- await expect(
- createRouter({
- logger: getVoidLogger(),
- preparers: new Preparers(),
- templaters: new Templaters(),
- publishers: new Publishers(),
- config: new ConfigReader(workDirConfig('/path')),
- database: createDatabase(),
- catalogClient: createCatalogClient([template]),
- reader: mockUrlReader,
- }),
- ).rejects.toThrow('access error');
- });
-
- it('should use the working directory when configured', async () => {
- const router = await createRouter({
- logger: getVoidLogger(),
- preparers: mockPreparers,
- templaters: new Templaters(),
- publishers: new Publishers(),
- config: new ConfigReader(workDirConfig('/path')),
- database: createDatabase(),
- catalogClient: createCatalogClient([template]),
- reader: mockUrlReader,
- });
-
- const app = express().use(router);
- await request(app)
- .post('/v1/jobs')
- .send({
- templateName: '',
- values: {
- storePath: 'https://github.com/backstage/good',
- },
- });
-
- expect(mockPrepare).toBeCalledWith({
- logger: expect.anything(),
- workspacePath: expect.stringContaining('path'),
- url: expect.anything(),
- });
- });
-
- it('should not pass along anything when no working directory is configured', async () => {
- const router = await createRouter({
- logger: getVoidLogger(),
- preparers: mockPreparers,
- templaters: new Templaters(),
- publishers: new Publishers(),
- config: new ConfigReader({}),
- database: createDatabase(),
- catalogClient: createCatalogClient([template]),
- reader: mockUrlReader,
- });
-
- const app = express().use(router);
- await request(app)
- .post('/v1/jobs')
- .send({
- templateName: '',
- values: {
- storePath: 'https://github.com/backstage/goodrepo',
- },
- });
-
- expect(mockPrepare).toBeCalledWith({
- logger: expect.anything(),
- workspacePath: expect.anything(),
- url: expect.anything(),
- });
- });
-});
-
describe('createRouter', () => {
let app: express.Express;
const template = {
@@ -239,21 +125,6 @@ describe('createRouter', () => {
jest.resetAllMocks();
});
- describe('POST /v1/jobs', () => {
- it('rejects template values which do not match the template schema definition', async () => {
- const response = await request(app)
- .post('/v1/jobs')
- .send({
- templateName: '',
- values: {
- storePath: 'https://github.com/backstage/backstage',
- },
- });
-
- expect(response.status).toEqual(400);
- });
- });
-
describe('GET /v2/actions', () => {
it('lists available actions', async () => {
const response = await request(app).get('/v2/actions').send();
diff --git a/plugins/scaffolder-backend/src/service/router.ts b/plugins/scaffolder-backend/src/service/router.ts
index 5e0790526e..dc8e69eb46 100644
--- a/plugins/scaffolder-backend/src/service/router.ts
+++ b/plugins/scaffolder-backend/src/service/router.ts
@@ -16,22 +16,16 @@
import { Config } from '@backstage/config';
import express from 'express';
-import { resolve as resolvePath, dirname } from 'path';
import Router from 'express-promise-router';
import { Logger } from 'winston';
import {
- JobProcessor,
PreparerBuilder,
TemplaterBuilder,
TemplaterValues,
PublisherBuilder,
- parseLocationAnnotation,
- joinGitUrlPath,
- FilePreparer,
} from '../scaffolder';
import { CatalogEntityClient } from '../lib/catalog';
-import { validate, ValidatorResult } from 'jsonschema';
-import parseGitUrl from 'git-url-parse';
+import { validate } from 'jsonschema';
import {
DatabaseTaskStore,
StorageTaskBroker,
@@ -101,7 +95,6 @@ export async function createRouter(
const logger = parentLogger.child({ plugin: 'scaffolder' });
const workingDirectory = await getWorkingDirectory(config, logger);
- const jobProcessor = await JobProcessor.fromConfig({ config, logger });
const entityClient = new CatalogEntityClient(catalogClient);
const integrations = ScmIntegrations.fromConfig(config);
@@ -137,134 +130,6 @@ export async function createRouter(
worker.start();
- router
- .get('/v1/job/:jobId', ({ params }, res) => {
- const job = jobProcessor.get(params.jobId);
-
- if (!job) {
- res.status(404).json({ error: 'job not found' });
- return;
- }
-
- res.json({
- id: job.id,
- metadata: {
- ...job.context,
- logger: undefined,
- logStream: undefined,
- },
- status: job.status,
- stages: job.stages.map(stage => ({
- ...stage,
- handler: undefined,
- })),
- error: job.error,
- });
- })
- .post('/v1/jobs', async (req, res) => {
- const templateName: string = req.body.templateName;
- const values: TemplaterValues = {
- ...req.body.values,
- destination: {
- git: parseGitUrl(req.body.values.storePath),
- },
- };
-
- // Forward authorization from client
- const template = await entityClient.findTemplate(templateName, {
- token: getBearerToken(req.headers.authorization),
- });
- if (!isAlpha1Template(template)) {
- throw new InputError(
- `This endpoint does not support templates with version ${template.apiVersion}`,
- );
- }
-
- const validationResult: ValidatorResult = validate(
- values,
- template.spec.schema,
- );
-
- if (!validationResult.valid) {
- res.status(400).json({ errors: validationResult.errors });
- return;
- }
-
- const job = jobProcessor.create({
- entity: template,
- values,
- stages: [
- {
- name: 'Prepare the skeleton',
- async handler(ctx) {
- const {
- protocol,
- location: templateEntityLocation,
- } = parseLocationAnnotation(ctx.entity);
-
- if (protocol === 'file') {
- const preparer = new FilePreparer();
-
- const path = resolvePath(
- dirname(templateEntityLocation),
- template.spec.path || '.',
- );
-
- await preparer.prepare({
- url: `file://${path}`,
- logger: ctx.logger,
- workspacePath: ctx.workspacePath,
- });
- return;
- }
-
- const preparer = preparers.get(templateEntityLocation);
-
- const url = joinGitUrlPath(
- templateEntityLocation,
- template.spec.path,
- );
-
- await preparer.prepare({
- url,
- logger: ctx.logger,
- workspacePath: ctx.workspacePath,
- });
- },
- },
- {
- name: 'Run the templater',
- async handler(ctx) {
- const templater = templaters.get(ctx.entity.spec.templater);
- await templater.run({
- workspacePath: ctx.workspacePath,
- logStream: ctx.logStream,
- values: ctx.values,
- });
- },
- },
- {
- name: 'Publish template',
- handler: async ctx => {
- const publisher = publishers.get(ctx.values.storePath);
- ctx.logger.info('Will now store the template');
- const result = await publisher.publish({
- values: ctx.values,
- workspacePath: ctx.workspacePath,
- logger: ctx.logger,
- });
- return result;
- },
- },
- ],
- });
-
- jobProcessor.run(job);
-
- res.status(201).json({ id: job.id });
- });
-
- // NOTE: The v2 API is unstable
router
.get(
'/v2/templates/:namespace/:kind/:name/parameter-schema',
@@ -359,8 +224,11 @@ export async function createRouter(
let taskSpec;
if (isAlpha1Template(template)) {
- const result = validate(values, template.spec.schema);
+ logger.warn(
+ `[DEPRECATION] - Template: ${template.metadata.name} has version ${template.apiVersion} which is going to be deprecated. Please refer to https://backstage.io/docs/features/software-templates/migrating-from-v1alpha1-to-v1beta2 for help on migrating`,
+ );
+ const result = validate(values, template.spec.schema);
if (!result.valid) {
res.status(400).json({ errors: result.errors });
return;
diff --git a/plugins/scaffolder/src/components/ScaffolderPage/ScaffolderPage.tsx b/plugins/scaffolder/src/components/ScaffolderPage/ScaffolderPage.tsx
index 4a482402f8..bc1bcefe1e 100644
--- a/plugins/scaffolder/src/components/ScaffolderPage/ScaffolderPage.tsx
+++ b/plugins/scaffolder/src/components/ScaffolderPage/ScaffolderPage.tsx
@@ -175,7 +175,10 @@ export const ScaffolderPageContents = () => {
{matchingEntities &&
matchingEntities?.length > 0 &&
matchingEntities.map(template => (
-